package io.gitee.caoxiaoyu97.log.sensitive.pattern;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class XmlConverter implements BaseConverter {

    private static Pattern pattern = Pattern.compile("[0-9a-zA-Z]");

    // 日志脱敏开关
    protected String converterCanRun = "true";
    // 匹配深度
    protected Integer depth = 12;
    //单条消息的最大长度，主要是message
    protected Integer maxLength = 2048;
    // 日志脱敏关键字
    protected static Map<String,String> keywordMap = new HashMap<>();

    XmlConverter(String converterCanRun,Integer maxLength,Map keywordMap){
        this.converterCanRun  = converterCanRun;
        this.maxLength = maxLength;
        this.keywordMap = keywordMap;
    }

    @Override
    public boolean canConverter() {
        return Boolean.valueOf(this.converterCanRun) && !keywordMap.isEmpty();
    }

    @Override
    public String convert(String oriLogMsg) {
        if (oriLogMsg == null || oriLogMsg.isEmpty()) {
            return oriLogMsg;
        }
        //如果超长截取
        if (oriLogMsg.length() > maxLength) {
            oriLogMsg = oriLogMsg.substring(0, maxLength) + "<<<";//后面增加三个终止符
        }
        return invokeMsg(oriLogMsg);
    }

    public String invokeMsg(final String oriMsg){
        String tempMsg = oriMsg;
        try {

            Set<String> keysArray = keywordMap.keySet();
            for(String key: keysArray){
                int index = -1;
                int i = 0;
                do{
                    index = tempMsg.indexOf(key, index + 1);
                    if(index != -1){
                        if(isWordChar(tempMsg, key, index)){
                            continue;
                        }
                        int valueStart = getValueStartIndex(tempMsg, index + key.length());
                        if(valueStart > -1) {
                            int valueEnd = getValueEndEIndex(tempMsg, valueStart);
                            if(valueEnd>valueStart){
                            // 对获取的值进行脱敏
                                String subStr = tempMsg.substring(valueStart, valueEnd);
                                subStr = SensitiveDataConverter.facade(subStr, keywordMap.get(key));
                                tempMsg = tempMsg.substring(0,valueStart) + subStr + tempMsg.substring(valueEnd);
                            }
                        }
                    }
                }while(index != -1 );
            }
        } catch (Exception e) {
            return tempMsg;
        }
        return tempMsg;
    }

    /**
     * 判断key是否为单词内字符
     * @param msg 待检查字符串
     * @param key 关键字
     * @param index 起始位置
     * @return 判断结果
     */
    private boolean isWordChar(String msg, String key, int index){
        if(index != 0){
            // 判断key前面一个字符
            char preCh = msg.charAt(index-1);
            Matcher match = pattern.matcher(preCh + "");
            if(match.matches()){
                return true;
            }
        }
        // 判断key后面一个字符
        char nextCh = msg.charAt(index + key.length());
        Matcher match = pattern.matcher(nextCh + "");
        if(match.matches()){
            return true;
        }
        return false;
    }

    /**
     * 寻找key对应值的开始位置
     * @param msg 待检查字符串
     * @param valueStart 开始寻找位置
     * @return key对应值的开始位置
     */
    private int getValueStartIndex(String msg, int valueStart ){
        do{
            char ch = msg.charAt(valueStart);
            if(ch == '>'){
                break;
            }else{
                valueStart ++;
            }
        }while(true);

        return ++valueStart;
    }

    /**
     * 寻找key对应值的结束位置
     * @param msg 待检查字符串
     * @param valueEnd 开始寻找位置
     * @return key对应值的结束位置
     */
    private int getValueEndEIndex(String msg, int valueEnd){
        do{
            if(valueEnd == msg.length()){
                break;
            }
            char ch = msg.charAt(valueEnd);

            if (ch =='<'){
                break;
            }else{
                valueEnd ++;
            }
        }while(true);

        return valueEnd;
    }
}
